# -*- coding: utf-8 -*-
"""
日志分析系统主程序入口
启动各组件进程
"""

import os
import sys
import time
import signal
import multiprocessing
from multiprocessing import Process, Queue
from common.logger import get_logger
from common.config import config
from log_access.log_accessor import LogAccessor
from log_preprocess.log_preprocessor import LogPreprocessor
from log_analyze.log_analyzer import LogAnalyzer
from alarm_push.alarm_pusher import AlarmPusher
from web.app import create_app

logger = get_logger(__name__)


class LogAnalysisSystem:
    """日志分析系统主类"""
    
    def __init__(self):
        """初始化系统"""
        self.processes = {}
        self.queues = {}
        self.running = False
        
        # 创建进程间通信队列
        self.queues['log_queue'] = Queue()
        self.queues['preprocess_queue'] = Queue()
        self.queues['analyze_queue'] = Queue()
        self.queues['alarm_queue'] = Queue()
        
        # 获取进程配置
        self.process_config = config.get('processes', {})
    
    def start_log_access_processes(self):
        """启动日志接入进程"""
        process_count = self.process_config.get('log_access', 2)
        
        for i in range(process_count):
            process_name = f'log_access_{i+1}'
            process = Process(
                target=self._log_access_worker,
                name=process_name,
                args=(i, self.queues['log_queue'])
            )
            process.start()
            self.processes[process_name] = process
            logger.info(f"启动日志接入进程: {process_name}")
    
    def start_preprocess_processes(self):
        """启动预处理进程"""
        process_count = self.process_config.get('log_preprocess', 3)
        
        for i in range(process_count):
            process_name = f'log_preprocess_{i+1}'
            process = Process(
                target=self._preprocess_worker,
                name=process_name,
                args=(i, self.queues['log_queue'], self.queues['preprocess_queue'])
            )
            process.start()
            self.processes[process_name] = process
            logger.info(f"启动预处理进程: {process_name}")
    
    def start_analyze_processes(self):
        """启动分析进程"""
        process_count = self.process_config.get('log_analyze', 2)
        
        for i in range(process_count):
            process_name = f'log_analyze_{i+1}'
            process = Process(
                target=self._analyze_worker,
                name=process_name,
                args=(i, self.queues['preprocess_queue'], self.queues['analyze_queue'])
            )
            process.start()
            self.processes[process_name] = process
            logger.info(f"启动分析进程: {process_name}")
    
    def start_alarm_processes(self):
        """启动告警进程"""
        process_count = self.process_config.get('alarm_push', 1)
        
        for i in range(process_count):
            process_name = f'alarm_push_{i+1}'
            process = Process(
                target=self._alarm_worker,
                name=process_name,
                args=(i, self.queues['analyze_queue'], self.queues['alarm_queue'])
            )
            process.start()
            self.processes[process_name] = process
            logger.info(f"启动告警进程: {process_name}")
    
    def start_web_server(self):
        """启动Web服务器"""
        process_name = 'web_server'
        process = Process(
            target=self._web_server_worker,
            name=process_name
        )
        process.start()
        self.processes[process_name] = process
        logger.info(f"启动Web服务器: {process_name}")
    
    def _log_access_worker(self, worker_id: int, log_queue: Queue):
        """日志接入工作进程"""
        try:
            logger.info(f"日志接入工作进程 {worker_id} 启动")
            accessor = LogAccessor()
            
            while self.running:
                try:
                    # 从ES获取日志
                    logs = accessor.fetch_recent_logs(minutes=5)
                    
                    if logs:
                        # 推送到队列
                        for log in logs:
                            log_queue.put(log)
                        
                        logger.info(f"工作进程 {worker_id} 推送了 {len(logs)} 条日志")
                    
                    # 等待下次检查
                    time.sleep(60)
                    
                except Exception as e:
                    logger.error(f"日志接入工作进程 {worker_id} 错误: {e}")
                    time.sleep(10)
            
            accessor.close()
            logger.info(f"日志接入工作进程 {worker_id} 退出")
            
        except Exception as e:
            logger.error(f"日志接入工作进程 {worker_id} 异常退出: {e}")
    
    def _preprocess_worker(self, worker_id: int, log_queue: Queue, preprocess_queue: Queue):
        """预处理工作进程"""
        try:
            logger.info(f"预处理工作进程 {worker_id} 启动")
            preprocessor = LogPreprocessor()
            
            while self.running:
                try:
                    # 从队列获取日志
                    if not log_queue.empty():
                        logs = []
                        for _ in range(100):  # 批量处理
                            if not log_queue.empty():
                                logs.append(log_queue.get_nowait())
                            else:
                                break
                        
                        if logs:
                            # 预处理日志
                            result = preprocessor.process_and_store_logs(logs)
                            logger.info(f"工作进程 {worker_id} 处理了 {len(logs)} 条日志")
                            
                            # 推送到分析队列
                            for log in logs:
                                preprocess_queue.put(log)
                    
                    time.sleep(1)
                    
                except Exception as e:
                    logger.error(f"预处理工作进程 {worker_id} 错误: {e}")
                    time.sleep(5)
            
            preprocessor.close()
            logger.info(f"预处理工作进程 {worker_id} 退出")
            
        except Exception as e:
            logger.error(f"预处理工作进程 {worker_id} 异常退出: {e}")
    
    def _analyze_worker(self, worker_id: int, preprocess_queue: Queue, analyze_queue: Queue):
        """分析工作进程"""
        try:
            logger.info(f"分析工作进程 {worker_id} 启动")
            analyzer = LogAnalyzer()
            
            while self.running:
                try:
                    # 从队列获取日志
                    if not preprocess_queue.empty():
                        logs = []
                        for _ in range(50):  # 批量处理
                            if not preprocess_queue.empty():
                                logs.append(preprocess_queue.get_nowait())
                            else:
                                break
                        
                        if logs:
                            # 分析日志
                            result = analyzer.analyze_and_store_logs(logs)
                            logger.info(f"工作进程 {worker_id} 分析了 {len(logs)} 条日志")
                            
                            # 推送到告警队列
                            for log in logs:
                                analyze_queue.put(log)
                    
                    time.sleep(1)
                    
                except Exception as e:
                    logger.error(f"分析工作进程 {worker_id} 错误: {e}")
                    time.sleep(5)
            
            analyzer.close()
            logger.info(f"分析工作进程 {worker_id} 退出")
            
        except Exception as e:
            logger.error(f"分析工作进程 {worker_id} 异常退出: {e}")
    
    def _alarm_worker(self, worker_id: int, analyze_queue: Queue, alarm_queue: Queue):
        """告警工作进程"""
        try:
            logger.info(f"告警工作进程 {worker_id} 启动")
            alarm_pusher = AlarmPusher()
            
            while self.running:
                try:
                    # 从队列获取日志
                    if not analyze_queue.empty():
                        logs = []
                        for _ in range(100):  # 批量处理
                            if not analyze_queue.empty():
                                logs.append(analyze_queue.get_nowait())
                            else:
                                break
                        
                        if logs:
                            # 处理告警
                            result = alarm_pusher.process_logs_for_alarms(logs)
                            logger.info(f"工作进程 {worker_id} 处理了 {len(logs)} 条日志的告警")
                    
                    time.sleep(1)
                    
                except Exception as e:
                    logger.error(f"告警工作进程 {worker_id} 错误: {e}")
                    time.sleep(5)
            
            alarm_pusher.close()
            logger.info(f"告警工作进程 {worker_id} 退出")
            
        except Exception as e:
            logger.error(f"告警工作进程 {worker_id} 异常退出: {e}")
    
    def _web_server_worker(self):
        """Web服务器工作进程"""
        try:
            logger.info("Web服务器启动")
            app = create_app()
            
            host = config.get('web.host', '0.0.0.0')
            port = config.get('web.port', 5000)
            debug = config.get('web.debug', False)
            
            app.run(host=host, port=port, debug=debug)
            
        except Exception as e:
            logger.error(f"Web服务器异常退出: {e}")
    
    def start(self):
        """启动系统"""
        logger.info("启动日志分析系统")
        self.running = True
        
        try:
            # 启动各组件进程
            self.start_log_access_processes()
            self.start_preprocess_processes()
            self.start_analyze_processes()
            self.start_alarm_processes()
            self.start_web_server()
            
            logger.info("所有进程启动完成")
            
            # 等待进程结束
            while self.running:
                time.sleep(1)
                
                # 检查进程状态
                for name, process in self.processes.items():
                    if not process.is_alive():
                        logger.error(f"进程 {name} 已退出")
                        self.running = False
                        break
            
        except KeyboardInterrupt:
            logger.info("收到中断信号，正在关闭系统")
        except Exception as e:
            logger.error(f"系统运行异常: {e}")
        finally:
            self.stop()
    
    def stop(self):
        """停止系统"""
        logger.info("正在停止日志分析系统")
        self.running = False
        
        # 停止所有进程
        for name, process in self.processes.items():
            try:
                if process.is_alive():
                    process.terminate()
                    process.join(timeout=10)
                    if process.is_alive():
                        process.kill()
                    logger.info(f"进程 {name} 已停止")
            except Exception as e:
                logger.error(f"停止进程 {name} 失败: {e}")
        
        # 清空队列
        for queue_name, queue in self.queues.items():
            try:
                while not queue.empty():
                    queue.get_nowait()
            except Exception as e:
                logger.error(f"清空队列 {queue_name} 失败: {e}")
        
        logger.info("日志分析系统已停止")


def signal_handler(signum, frame):
    """信号处理器"""
    logger.info(f"收到信号 {signum}，正在关闭系统")
    sys.exit(0)


def main():
    """主函数"""
    # 设置信号处理
    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)
    
    # 设置多进程启动方法
    multiprocessing.set_start_method('spawn', force=True)
    
    try:
        # 创建并启动系统
        system = LogAnalysisSystem()
        system.start()
    except Exception as e:
        logger.error(f"系统启动失败: {e}")
        sys.exit(1)


if __name__ == '__main__':
    main() 